#include "BernsteinPol.h"

#include <cmath>


void BernsteinPol::init(unsigned int grado) {
	std::vector< double > vecCoeficientes;

	// Calcula los coeficientes del polinomio
	for (unsigned int i = 0; i <= grado; ++i){
		double coefTemp = combinatoria(grado, i);
		vecCoeficientes.push_back( coefTemp );
	}

	this->m_grado = grado;
	this->m_coefComb.swap( vecCoeficientes );
}


double BernsteinPol::eval(double u, unsigned int k) const {
	//P(u, k) = ( n!/( k!(n-k)! ) ) * u^k * (1-u)^(n-k)
	return this->m_coefComb[k] * evalPartePolinomial(u, this->m_grado, k);
}


double BernsteinPol::evalPartePolinomial(double u, unsigned int n, unsigned int k) const {
	// u^k
	double uk = std::pow(u, k);

	// (1-u)^(n-k)
	double unoU = 1.0 - u;
	double nk = static_cast<double>(n - k);
	double unk = std::pow( unoU, nk );

	// La cuenta es: "u^k * (1-u)^(n-k)"
	return uk * unk;
}


// Una forma mas eficiente de calcular la combinatoria, me lo robe de internet
double BernsteinPol::combinatoria(unsigned int n, unsigned int k) const {
	// El primer y el ultimo coeficiente del polinomio es siempre "1"
	if (k == 0 || k == n || n == 0) return 1.0;

	return combinatoria( n -1, k -1 ) * n / k;
}